package org.example.gradlegateway.filter;

import gradle.common.core.constants.MediaType;
import gradle.common.core.constants.SecurityConstant;
import gradle.common.core.enums.ResultCodeEnum;
import gradle.common.core.exception.InvalidBearerTokenException;
import gradle.common.core.utils.JsonUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.example.gradlegateway.model.ResponseEntity;
import org.example.gradlegateway.properties.CustomizeGatewayProperties;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;

/**
 * 网关白名单及TOKEN校验
 */
@Slf4j
@Component
public class CustomizeValidateFilter implements GlobalFilter, Ordered {

    @Resource
    private JwtDecoder jwtDecoder;

    private final AntPathMatcher matcher = new AntPathMatcher();

    @Resource
    private CustomizeGatewayProperties customizeGatewayProperties;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String path = exchange.getRequest().getPath().toString();

        // 检查是否在白名单中
        boolean isWhiteListPath = isWhiteListPath(path);
        if (isWhiteListPath) {
            // 直接放行，不进行后续过滤器处理
            return chain.filter(exchange);
        }

        //token 验证
        Jwt jwt = validateToken(exchange);
        if (jwt != null) {
            // 提取关键参数并写入请求头
            ServerHttpRequest mutatedRequest = exchange.getRequest().mutate()
                    .header(SecurityConstant.USER_ID, jwt.getClaimAsString(SecurityConstant.USER_ID))
                    .header(SecurityConstant.USERNAME, jwt.getClaimAsString(SecurityConstant.USERNAME))
                    .header(SecurityConstant.AUTHORITIES, jwt.getClaimAsString(SecurityConstant.AUTHORITIES))
                    .build();
            return chain.filter(exchange.mutate().request(mutatedRequest).build());
        }

        // 验证失败，返回 401 Unauthorized 响应
        return unauthorizedResponse(exchange);
    }

    /**
     * token验证
     *
     * @param exchange exchange
     * @return Jwt
     */
    private Jwt validateToken(ServerWebExchange exchange) {
        //从请求头提取 JWT Token
        String accessToken = exchange.getRequest().getHeaders().getFirst(HttpHeaders.AUTHORIZATION);

        if (StringUtils.isBlank(accessToken)) {
            throw new InvalidBearerTokenException();
        }
        // 去掉 "Bearer " 前缀
        boolean startsWith = accessToken.startsWith("Bearer ");
        if (!startsWith) {
            throw new InvalidBearerTokenException();
        }
        accessToken = accessToken.substring(7);
        return jwtDecoder.decode(accessToken);
    }

    private boolean isWhiteListPath(String path) {
        return customizeGatewayProperties.getWhiteList().stream()
                .anyMatch(pattern -> matcher.match(pattern, path));
    }


    @Override
    public int getOrder() {
        // 设置过滤器执行顺序（越小越先执行）
        return Ordered.HIGHEST_PRECEDENCE; // 最高优先级
    }

    /**
     * 构造 401 Unauthorized 响应
     */
    private Mono<Void> unauthorizedResponse(ServerWebExchange exchange) {
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(HttpStatus.UNAUTHORIZED); // 设置 401 状态码
        response.getHeaders().add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE);
        // 构造响应体
        ResponseEntity responseEntity = new ResponseEntity(ResultCodeEnum.UNAUTHORIZED.getCode(), ResultCodeEnum.UNAUTHORIZED.getMessage());
        // 将响应体写入并返回 Mono<Void>
        DataBufferFactory bufferFactory = response.bufferFactory();
        DataBuffer buffer = bufferFactory.wrap(JsonUtil.toJsonString(responseEntity).getBytes(StandardCharsets.UTF_8));
        return response.writeWith(Mono.just(buffer));
    }
}